home *** CD-ROM | disk | FTP | other *** search
- /*** analog 1.9beta ***/
- /* Please read Readme.html, or http://www.statslab.cam.ac.uk/~sret1/analog/ */
-
- #include "analhea2.h"
-
- /*** hash.c; the functions which do all the work in the hash tables. ***/
-
- /*** The first few are all exactly the same, adding a certain number of
- requests and a certain number of bytes to the hash entry for that item,
- creating a new hash entry if none existed before. ***/
-
- extern void *xmalloc(); /* in utils.c */
- /* used in so many functions, I declare it here */
-
- void hashadd(struct genstruct *objhead[], int hashsize, char *name, int reqs,
- double bytes, flag last7q, int *totalobjs,
- int *totalobjs7, int *totalnew7, flag al)
- {
- extern int magicno(); /* in utils.c */
-
- int magicnumber;
- flag finished;
- struct genstruct *p, *lastp, *prevp;
-
- /* First calculate name's "magic number" */
-
- magicnumber = magicno(name, hashsize);
-
- /* Now look through the magicnumber'th list for that URL */
-
- finished = FALSE;
- p = (objhead[magicnumber]);
- lastp = p;
- prevp = p;
- while (p -> name != NULL && !finished) {
- if (STREQ(p -> name, name)) { /* then done */
- p -> reqs += reqs;
- p -> bytes += bytes;
- if (last7q && !(p -> last7)) {
- (*totalobjs7)++;
- p -> last7 = TRUE;
- }
- if (!last7q && !(p -> pre7)) {
- p -> pre7 = TRUE;
- (*totalnew7)--; /* Must have p -> last7, so have wrongly
- counted it as new in last 7 */
- }
- /* keep the list in rough (not exact) order of number of
- accesses for quicker searching; particularly useful if
- the HASHSIZE is set too low. */
- if (p -> reqs > lastp -> reqs) {
- if (prevp == lastp) { /* iff p is 2nd in the list */
- objhead[magicnumber] = p;
- lastp -> next = p -> next;
- p -> next = lastp;
- }
- else { /* p is 3rd or later in the list */
- prevp -> next = p;
- lastp -> next = p -> next;
- p -> next = lastp;
- }
- }
- finished = TRUE;
- }
- else { /* look at the next one */
- prevp = lastp;
- lastp = p;
- p = p -> next;
- }
- }
-
- if (!finished) { /* reached the end of the list without success; new one */
- (*totalobjs)++;
- p -> name = (char *)xmalloc((size_t)((int)strlen(name) + 1));
- strcpy(p -> name, name);
- p -> reqs = reqs;
- p -> bytes = bytes;
- p -> aliasdone = al;
- if (last7q) {
- (*totalobjs7)++;
- (*totalnew7)++;
- p -> last7 = TRUE;
- p -> pre7 = FALSE;
- }
- else {
- p -> last7 = FALSE;
- p -> pre7 = TRUE;
- }
- p -> next = (struct genstruct *)xmalloc(sizeof(struct genstruct));
- p -> next -> name = NULL;
- }
- }
-
- /*** The domain hashadd function is different from the others, because we
- already know all domains, so there need be no clashes in the hash table. ***/
-
- void domhashadd(char *hostn, int reqs, double bytes)
- {
- extern int hosttodomcode(); /* in alias.c */
- extern flag subdomadd(); /* in this file */
- extern int magicno(); /* in utils.c */
-
- extern struct domain *domainhead[], *subdomhead[], *wildsubdomhead,
- *nwildsubdomhead;
- extern int debug;
-
- int domcode; /* domcode is as explained at the bit where we read the
- domains in. It's the equivalent of magic number for
- the other hashadd functions. */
- int magicnumber; /* for subdomains */
- flag finished;
- struct domain *domp;
- char *tempp;
- char tempchar;
-
- domcode = hosttodomcode(hostn);
- if (domcode == DOMHASHSIZE - 2 && debug >= 2)
- fprintf(stderr, "U: %s\n", hostn);
-
- domainhead[domcode] -> reqs += reqs;
- domainhead[domcode] -> bytes += bytes;
-
- /* Next run through the list of wild subdomains. There are two cases;
- numerical and ordinary subdomains */
-
- if (!isdigit(hostn[(int)strlen(hostn) - 1])) { /* non-numerical */
-
- for (domp = wildsubdomhead; domp -> id != NULL; domp = domp -> next) {
- if(STREQ(domp -> id,
- hostn + MAX((int)strlen(hostn) - (int)strlen(domp -> id), 0))) {
- /* run back to just after the previous . (or the initial character) */
- tempp = hostn + MAX((int)strlen(hostn) - (int)strlen(domp -> id), 0);
- while (tempp != hostn && *(tempp - 1) != '.')
- tempp--;
- /* now add that one to the list of subdoms; it will get looked at
- in the next stage */
- subdomadd(tempp, "?");
- }
- }
-
- /* now run through the subdomains this hostname could belong to and see
- if any of them are required to be analysed */
-
- tempp = strrchr(hostn, '.'); /* the final dot */
-
- if (tempp != NULL) {
-
- while (tempp != hostn) {
- tempp--;
- while (tempp != hostn && *(tempp - 1) != '.')
- tempp--;
- magicnumber = magicno(tempp, SUBDOMHASHSIZE);
- finished = OFF;
- for (domp = subdomhead[magicnumber]; domp -> name != NULL && !finished;
- domp = domp -> next) {
- if (STREQ(domp -> id, tempp)) {
- domp -> reqs += reqs;
- domp -> bytes += bytes;
- finished = ON;
- }
- }
- }
- }
-
- } /* end non-numerical subdomains; now do numerical ones */
-
- else {
-
- /* wild numerical subdomains */
-
- for (domp = nwildsubdomhead; domp -> id != NULL; domp = domp -> next) {
- if(strncmp(domp -> id, hostn, (size_t)(int)strlen(domp -> id)) == 0) {
- /* run to the next . (or the end) */
- tempp = hostn + (int)strlen(domp -> id);
- while (*tempp != '.' && *tempp != '\0')
- tempp++;
- /* now add that one to the subdoms */
- tempchar = *tempp;
- *tempp = '\0'; /* temporarily trucate the string after the subdom */
- subdomadd(hostn, "?");
- *tempp = tempchar;
- }
- }
-
- /* and now run through the ordinary subdoms for this numerical host */
-
- tempp = hostn + (int)strlen(hostn);
-
- while (tempp != hostn) {
- while (tempp != hostn && *tempp != '.' && *tempp != '\0')
- tempp--;
- if (tempp != hostn) {
- tempchar = *tempp;
- *tempp = '\0'; /* temporarily trucate the string again */
- magicnumber = magicno(hostn, SUBDOMHASHSIZE);
- finished = OFF;
- for (domp = subdomhead[magicnumber]; domp -> name != NULL && !finished;
- domp = domp -> next) {
- if (STREQ(domp -> id, hostn)) {
- domp -> reqs += reqs;
- domp -> bytes += bytes;
- finished = ON;
- }
- }
- *tempp = tempchar;
- tempp--;
- }
- }
- }
-
- }
-
- /*** Add a new subdomain to the list of subdomains ***/
-
- flag subdomadd(char *id, char *name)
- {
- extern char *reversehostname(); /* in alias.c */
-
- extern struct domain *subdomhead[SUBDOMHASHSIZE];
- extern struct domain *wildsubdomhead, *nwildsubdomhead;
-
- struct domain *domp, *domnextp;
- int magicnumber;
- flag numeric; /* whether it's a numerical subdomain */
-
- if (id[0] == '?') /* we don't want it */
- ;
-
- else if (id[0] == '*') { /* put at start wild list (order doesn't matter) */
- domnextp = wildsubdomhead;
- wildsubdomhead = (struct domain *)xmalloc(sizeof(struct domain));
- wildsubdomhead -> next = domnextp;
- wildsubdomhead -> id = xmalloc((size_t)((int)strlen(id)));
- strcpy(wildsubdomhead -> id, id + 1);
- }
-
- else if (id[(int)strlen(id) - 1] == '*') {
- domnextp = nwildsubdomhead;
- nwildsubdomhead = (struct domain *)xmalloc(sizeof(struct domain));
- nwildsubdomhead -> next = domnextp;
- nwildsubdomhead -> id = xmalloc((size_t)((int)strlen(id)));
- strncpy(nwildsubdomhead -> id, id, (size_t)((int)strlen(id) - 1));
- *(nwildsubdomhead -> id + (int)strlen(id) - 1) = '\0';
- }
-
- else if (id[0] == '%') { /* token representing "all numerical domains" */
- domnextp = nwildsubdomhead;
- nwildsubdomhead = (struct domain *)xmalloc(sizeof(struct domain));
- nwildsubdomhead -> next = domnextp;
- nwildsubdomhead -> id = xmalloc(1);
- nwildsubdomhead -> id[0] = '\0';
- }
-
- else {
- magicnumber = magicno(id, SUBDOMHASHSIZE);
- domp = subdomhead[magicnumber];
-
- /* look through that list and slot it in alphabetically
- (for quicker finding than random if it's repeated later) */
-
- if (!isdigit(id[(int)strlen(id) - 1])) {
- reversehostname(id);
- numeric = FALSE;
- }
- else
- numeric = TRUE;
-
- /* if it goes at the beginning of the list, slot it in there */
- if (domp -> name == NULL || strcmp(domp -> revid, id) > 0) {
- domnextp = domp;
- domp = (struct domain *)xmalloc(sizeof(struct domain));
- subdomhead[magicnumber] = domp;
- domp -> revid = xmalloc((size_t)((int)strlen(id) + 1));
- strcpy(domp -> revid, id);
- domp -> id = xmalloc((size_t)((int)strlen(id) + 1));
- if (!numeric)
- reversehostname(id);
- strcpy(domp -> id, id);
- domp -> name = xmalloc((size_t)((int)strlen(name) + 1));
- strcpy(domp -> name, name);
- domp -> reqs = 0;
- domp -> bytes = 0;
- domp -> next = domnextp;
- return(TRUE);
- }
- else if (strcmp(domp -> revid, id) == 0) {
- if (!numeric)
- reversehostname(id);
- return(FALSE);
- }
- else { /* run to right place in alphabet */
- while (domp -> next -> name != NULL &&
- strcmp(domp -> next -> revid, id) < 0)
- domp = domp -> next;
- if (domp -> next -> name != NULL &&
- strcmp(domp -> next -> revid, id) == 0) {
- if (!numeric)
- reversehostname(id); /* so as to leave it unchanged on exit */
- return(FALSE);
- }
- else {
- domnextp = domp -> next;
- domp -> next = (struct domain *)xmalloc(sizeof(struct domain));
- domp = domp -> next;
- domp -> revid = xmalloc((size_t)((int)strlen(id) + 1));
- strcpy(domp -> revid, id);
- domp -> id = xmalloc((size_t)((int)strlen(id) + 1));
- if (!numeric)
- reversehostname(id);
- strcpy(domp -> id, id);
- domp -> name = xmalloc((size_t)((int)strlen(name) + 1));
- strcpy(domp -> name, name);
- domp -> reqs = 0;
- domp -> bytes = 0;
- domp -> next = domnextp;
- return(TRUE);
- }
- }
- }
- }
-
- /*** Check if we want a certain referer, and add it ***/
-
- void addref(char *fromurl, char *filename, double bytes, flag last7q,
- flag filemaskq) /* last ON if extern one ON and not yet done */
- {
- extern flag refmaskq;
- extern struct genstruct *refhead[];
- extern struct include *wantrefhead, *wantfilehead;
-
- flag wantthisone;
- int tempint;
-
- if (refmaskq)
- wantthisone = (doaliasref(fromurl) != -1) &&
- included(fromurl, wantrefhead);
- if (wantthisone && filemaskq)
- wantthisone = included(filename, wantfilehead);
- if (wantthisone)
- hashadd(refhead, REFHASHSIZE, fromurl, 1, bytes, last7q,
- &tempint, &tempint, &tempint, OFF);
- }
-
- /*** Process a browser line, and add it to the lists ***/
- /* (Little to do, so we don't use a browser alias function) */
-
- void addbrowser(char *browser, double bytes, flag last7q)
- {
- extern flag bq, Bq;
- extern struct genstruct *browhead[], *fullbrowhead[];
-
- char *c;
- int tempint;
-
- /* cut (illegal) "via"s (e.g., via proxy gateway or via Harvest cache) */
- if ((c = strstr(browser, " via ")) != NULL) {
- while (*c != ' ' && c != browser)
- c--;
- *(c + 1) = '\0';
- }
-
- /* add to full browser report */
- if (Bq)
- hashadd(fullbrowhead, FULLBROWHASHSIZE, browser, 1, bytes,
- last7q, &tempint, &tempint, &tempint, OFF);
-
- if (bq) {
- /* generate shortened name */
- if ((c = strchr(browser, '/')) != NULL)
- *c = '\0';
-
- /* two special cases */
- if (STREQ(browser, "Mozilla"))
- strcpy(browser, "Netscape");
- else if (strstr(browser, "Mosaic") != NULL ||
- strstr(browser, "mosaic") != NULL)
- strcpy(browser, "Mosaic");
-
- /* and add to browser summary */
- hashadd(browhead, BROWHASHSIZE, browser, 1, bytes,
- last7q, &tempint, &tempint, &tempint, OFF);
- }
- }
-
- /*** And one to add an error to the list of errors ***/
-
- void adderr(char *errstr)
- {
- extern char *strtoupper(); /* in utils.c */
-
- extern char errs[NO_ERRS][MAXERRLENGTH];
- extern int errors[NO_ERRS];
- extern int debug;
-
- char e1[MAXLINELENGTH], e2[MAXSTRINGLENGTH];
- int i;
- flag done = OFF;
-
- for (i = 0; !done; i++) {
- strcpy(e1, errstr);
- strcpy(e2, errs[i]);
- if (strstr(strtoupper(e1), strtoupper(e2)) != NULL) {
- done = ON;
- errors[i]++;
- if (debug >= 2 && i == NO_ERRS - 1) /* unknown error type */
- fprintf(stderr, "E: %s\n", errstr);
- }
- }
- }
-
- /*** Next a function to do an approx count of the number of distinct hosts ***/
- /* First some utilities for it */
-
- flag approxhostfilled(char *space, int i)
- { /* whether there is already a 1 at entry i of the table */
- int j, k;
-
- j = i / 8;
- k = i % 8;
-
- return((*(space + j) >> k) & 1);
- }
-
- void approxhostfill(char *space, int i)
- { /* put a 1 at entry i; ASSUMES IT IS CURRENTLY EMPTY */
- int j, k;
-
- j = i / 8;
- k = i % 8;
- *(space + j) += (1 << k);
-
- }
-
- void approxhosthashadd(char *hostn, flag last7q)
- {
- extern char *approxhostspace, *approxhostspace7;
- extern int approxhostsize;
- extern int no_hosts, no_hosts7, no_new_hosts7;
- extern flag q7;
-
- int magicnumber1, magicnumber2, magicnumber3, magicnumber4;
- flag seen1, seen2, seen3, seen4; /* whether we'd already seen that number */
- flag seen17, seen27, seen37, seen47; /* ditto in last 7 days */
- flag seen, seen7; /* whether we've seen all 4 numbers before */
- register int i;
- /* NB Note approxhostfill assumes empty; be careful about two equal magic
- numbers for some host */
-
- magicnumber1 = 0;
- for (i = 0; hostn[i] != '\0'; i++) {
- magicnumber1 = 101 * magicnumber1 + hostn[i];
- if (magicnumber1 < 0)
- magicnumber1 = -magicnumber1;
- while (magicnumber1 >= 8 * approxhostsize)
- magicnumber1 -= 8 * approxhostsize;
- }
- seen1 = approxhostfilled(approxhostspace, magicnumber1);
- if (!seen1 && (!q7 || !last7q)) /* if q7 only pre-last7 go here;
- if !q7 everything does */
- approxhostfill(approxhostspace, magicnumber1);
- if (q7) {
- seen17 = approxhostfilled(approxhostspace7, magicnumber1);
- if (!seen17 && last7q)
- approxhostfill(approxhostspace7, magicnumber1);
- }
-
- magicnumber2 = 0;
- for (i--; i >= 0; i--) {
- magicnumber2 = 101 * magicnumber2 + hostn[i];
- if (magicnumber2 < 0)
- magicnumber2 = -magicnumber2;
- while (magicnumber2 >= 8 * approxhostsize)
- magicnumber2 -= 8 * approxhostsize;
- }
- seen2 = approxhostfilled(approxhostspace, magicnumber2);
- if (!seen2 && (!q7 || !last7q))
- approxhostfill(approxhostspace, magicnumber2);
- if (q7) {
- seen27 = approxhostfilled(approxhostspace7, magicnumber2);
- if (!seen27 && last7q)
- approxhostfill(approxhostspace7, magicnumber2);
- }
-
- magicnumber3 = 0;
- for (i = 0; hostn[i] != '\0'; i++) {
- magicnumber3 = 103 * magicnumber3 + hostn[i];
- if (magicnumber3 < 0)
- magicnumber3 = -magicnumber3;
- while (magicnumber3 >= 8 * approxhostsize)
- magicnumber3 -= 8 * approxhostsize;
- }
- seen3 = approxhostfilled(approxhostspace, magicnumber3);
- if (!seen3 && (!q7 || !last7q))
- approxhostfill(approxhostspace, magicnumber3);
- if (q7) {
- seen37 = approxhostfilled(approxhostspace7, magicnumber3);
- if (!seen37 && last7q)
- approxhostfill(approxhostspace7, magicnumber3);
- }
-
- magicnumber4 = 0;
- for (i--; i >= 0; i--) {
- magicnumber4 = 103 * magicnumber4 + hostn[i];
- if (magicnumber4 < 0)
- magicnumber4 = -magicnumber4;
- while (magicnumber4 >= 8 * approxhostsize)
- magicnumber4 -= 8 * approxhostsize;
- }
- seen4 = approxhostfilled(approxhostspace, magicnumber4);
- if (!seen4 && (!q7 || !last7q))
- approxhostfill(approxhostspace, magicnumber4);
- if (q7) {
- seen47 = approxhostfilled(approxhostspace7, magicnumber4);
- if (!seen47 && last7q)
- approxhostfill(approxhostspace7, magicnumber4);
- seen7 = seen17 && seen27 && seen37 && seen47;
- }
-
- seen = seen1 && seen2 && seen3 && seen4;
-
- if (!q7) {
- if (!seen) /* new host */
- ++no_hosts;
- }
-
- else { /* q7 */
- if (!seen && !seen7) {
- ++no_hosts;
- if (last7q) {
- ++no_hosts7;
- ++no_new_hosts7;
- }
- }
- else if (!seen && seen7 && !last7q) /* it wasn't really a new host 7 */
- --no_new_hosts7;
- else if (seen && !seen7 && last7q)
- ++no_hosts7;
-
- } /* end else (= if q7) */
-
- } /* end approxhosthashadd() */
-
- /*** Next the functions to do with dates ***/
- /* add to the number of requests for a particular month */
- void addmonthlydata(int year, int monthno, int reqs, double bytes)
- {
- extern struct monthly *firstm, *lastm;
- extern struct timestruct firsttime, lasttime;
- extern flag mback;
-
- struct monthly *mp;
- int i;
-
- mp = mback?lastm:firstm;
-
- for (i = mback?(lasttime.year - year):(year - firsttime.year); i > 0; i--)
- mp = mp -> next; /* run to the right year */
-
- mp -> reqs[monthno] += reqs; /* and add to the right month in that year */
- mp -> bytes[monthno] += bytes;
-
- }
-
- /* add to the number of requests for a particular day */
- void adddailydata(int year, int monthno, int date, int reqs, double bytes)
- {
- extern struct daily *firstd, *lastd;
- extern struct timestruct firsttime, lasttime;
- extern flag Dback;
-
- struct daily *dp;
- int i;
-
- dp = Dback?lastd:firstd;
-
- for (i = Dback?((lasttime.year - year) * 12 + lasttime.monthno - monthno):
- ((year - firsttime.year) * 12 + monthno - firsttime.monthno);
- i > 0; i--)
- dp = dp -> next; /* run to the right month */
-
- dp -> reqs[date - 1] += reqs; /* and add to the right date */
- dp -> bytes[date - 1] += bytes;
-
- }
-
- /* add to the number of requests for a particular hour */
- void addhourlydata(int year, int monthno, int date, int hr, int reqs,
- double bytes)
- {
- extern struct hourly *firsth, *lasth;
- extern struct timestruct firsttime, lasttime;
- extern flag Hback;
-
- struct hourly *hp;
- int i;
-
- hp = Hback?lasth:firsth;
-
- for (i = Hback?minsbetween(date, monthno, year, 0, 0, lasttime.date,
- lasttime.monthno, lasttime.year, 0, 0) / 1440:
- minsbetween(firsttime.date, firsttime.monthno, firsttime.year, 0, 0,
- date, monthno, year, 0, 0) / 1440;
- i > 0; i--)
- hp = hp -> next; /* run to the right day */
-
- hp -> reqs[hr] += reqs; /* and add to the right hour */
- hp -> bytes[hr] += bytes;
-
- }
-
- /* add to the number of requests for a particular week */
- void addweeklydata(int year, int monthno, int date, int reqs, double bytes)
- {
- extern int minsbetween(); /* in utils.c */
-
- extern struct weekly *firstw, *lastw;
- extern flag Wback;
-
- struct weekly *wp;
-
- wp = Wback?lastw:firstw;
-
- while(minsbetween(wp -> start.date, wp -> start.monthno, wp -> start.year,
- 0, 0, date, monthno, year, 0, 0) * (Wback?(-1):1)
- >= (Wback?1:10080))
- wp = wp -> next; /* run to right week (when 0 <= minsbetween < 10080) */
-
- wp -> reqs += reqs; /* and add to its requests */
- wp -> bytes += bytes;
-
- }
-
- /* and a function to co-ordinate all the date cataloguing */
- void datehash(int year, int monthno, int date, int hr, int min,
- long thistimecode, int reqs, double bytes)
- {
- extern long timecode(); /* in utils.c */
-
- extern flag mq, dq, Dq, Wq, Hq;
- extern flag mback, Dback, Wback, Hback;
- extern struct timestruct firsttime, lasttime;
- extern struct monthly *firstm, *lastm;
- extern struct daily *firstd, *lastd;
- extern struct weekly *firstw, *lastw;
- extern struct hourly *firsth, *lasth;
- extern int monthlength[];
- extern int dailyreq[], hourlyreq[];
- extern double dailybytes[], hourlybytes[];
-
- int day;
- struct monthly *tempmp;
- struct daily *tempdp;
- struct weekly *tempwp;
- struct hourly *temphp;
- int i, j;
-
- if (mq) {
-
- if (year <= firsttime.year) { /* then we might need a new lot of months */
- for (i = firsttime.year - year; i > 0; i--) {
- tempmp = firstm;
- firstm = (struct monthly *)xmalloc(sizeof(struct monthly));
- if (mback) {
- tempmp -> next = firstm;
- firstm -> next = NULL;
- }
- else
- firstm -> next = tempmp;
- for (j = 0; j < 12; j++) {
- firstm -> reqs[j] = 0;
- firstm -> bytes[j] = 0.0;
- }
- }
- firstm -> reqs[monthno] += reqs; /* add to this month */
- firstm -> bytes[monthno] += bytes; /* (whether or not newly created) */
- }
-
- else if (year >= lasttime.year) { /* similarly */
- for (i = year - lasttime.year; i > 0; i--) {
- tempmp = lastm;
- lastm = (struct monthly *)xmalloc(sizeof(struct monthly));
- if (mback)
- lastm -> next = tempmp;
- else {
- tempmp -> next = lastm;
- lastm -> next = NULL;
- }
- for (j = 0; j < 12; j++) {
- lastm -> reqs[j] = 0;
- lastm -> bytes[j] = 0.0;
- }
- }
- lastm -> reqs[monthno] += reqs;
- lastm -> bytes[monthno] += bytes;
- }
-
- else /* NB we will never get here if logfile in chron. order */
- addmonthlydata(year, monthno, reqs, bytes);
-
- } /* end if (mq) */
-
- if (Dq) {
-
- if (year * 12 + monthno <= firsttime.year * 12 + firsttime.monthno) {
- /* then we might need a new lot of days */
- for (i = (firsttime.year - year) * 12 +
- firsttime.monthno - monthno; i > 0; i--) {
- tempdp = firstd;
- firstd = (struct daily *)xmalloc(sizeof(struct daily));
- if (Dback) {
- tempdp -> next = firstd;
- firstd -> next = NULL;
- }
- else
- firstd -> next = tempdp;
- for (j = 0; j < 31; j++) {
- firstd -> reqs[j] = 0;
- firstd -> bytes[j] = 0.0;
- }
- }
- firstd -> reqs[date - 1] += reqs;
- firstd -> bytes[date - 1] += bytes;
- }
-
- else
- if (year * 12 + monthno >= lasttime.year * 12 + lasttime.monthno) {
- for (i = (year - lasttime.year) * 12 - lasttime.monthno + monthno;
- i > 0; i--) {
- tempdp = lastd;
- lastd = (struct daily *)xmalloc(sizeof(struct daily));
- if (Dback)
- lastd -> next = tempdp;
- else {
- tempdp -> next = lastd;
- lastd -> next = NULL;
- }
- for (j = 0; j < 31; j++) {
- lastd -> reqs[j] = 0;
- lastd -> bytes[j] = 0.0;
- }
- }
- lastd -> reqs[date - 1] += reqs;
- lastd -> bytes[date - 1] += bytes;
- }
-
- else
- adddailydata(year, monthno, date, reqs, bytes);
-
- } /* end if (mq) */
-
- if (Hq) {
-
- if (year * /* 12 * 31 */ 372 + monthno * 31 + date <=
- firsttime.year * 372 + firsttime.monthno * 31 + firsttime.date) {
- /* then we might need a new lot of hours */
- for (i = minsbetween(date, monthno, year, 0, 0, firsttime.date,
- firsttime.monthno, firsttime.year, 0, 0) / 1440;
- i > 0; i--) {
- temphp = firsth;
- firsth = (struct hourly *)xmalloc(sizeof(struct hourly));
- if (Hback) {
- temphp -> next = firsth;
- firsth -> next = NULL;
- }
- else
- firsth -> next = temphp;
- for (j = 0; j < 24; j++) {
- firsth -> reqs[j] = 0;
- firsth -> bytes[j] = 0.0;
- }
- }
- firsth -> reqs[hr] += reqs;
- firsth -> bytes[hr] += bytes;
- }
-
- else
- if (year * 372 + monthno * 31 + date
- >= lasttime.year * 372 + lasttime.monthno * 31 + lasttime.date) {
- for (i = minsbetween(lasttime.date, lasttime.monthno, lasttime.year,
- 0, 0, date, monthno, year, 0, 0) / 1440;
- i > 0; i--) {
- temphp = lasth;
- lasth = (struct hourly *)xmalloc(sizeof(struct hourly));
- if (Hback)
- lasth -> next = temphp;
- else {
- temphp -> next = lasth;
- lasth -> next = NULL;
- }
- for (j = 0; j < 24; j++) {
- lasth -> reqs[j] = 0;
- lasth -> bytes[j] = 0.0;
- }
- }
- lasth -> reqs[hr] += reqs;
- lasth -> bytes[hr] += bytes;
- }
-
- else
- addhourlydata(year, monthno, date, hr, reqs, bytes);
-
- } /* end if (mq) */
-
- if (Wq) {
- if (thistimecode < firstw -> start.code) { /* new week needed */
- while (thistimecode < firstw -> start.code) {
- tempwp = firstw;
- firstw = (struct weekly *)xmalloc(sizeof(struct weekly));
- if (Wback) {
- tempwp -> next = firstw;
- firstw -> next = NULL;
- }
- else
- firstw -> next = tempwp;
- firstw -> reqs = 0;
- firstw -> bytes = 0.0;
- firstw -> start = tempwp -> start;
- firstw -> start.date -= 7;
- if (firstw -> start.date <= 0) {
- firstw -> start.monthno--;
- if (firstw -> start.monthno == -1) {
- firstw -> start.monthno = 11;
- firstw -> start.year--;
- }
- firstw -> start.date = monthlength[firstw -> start.monthno] +
- firstw -> start.date +
- ISLEAPFEB(firstw -> start.monthno, firstw -> start.year);
- }
- firstw -> start.code = timecode(firstw -> start.date,
- firstw -> start.monthno,
- firstw -> start.year, 0, 0);
- }
- firstw -> reqs += reqs;
- firstw -> bytes += bytes;
- }
-
- else if (thistimecode >= lastw -> start.code) {
- while (minsbetween(lastw -> start.date, lastw -> start.monthno,
- lastw -> start.year, 0, 0, /* 10080m = 1w */
- date, monthno, year, 0, 0) >= 10080) {
- tempwp = lastw;
- lastw = (struct weekly *)xmalloc(sizeof(struct weekly));
- if (Wback)
- lastw -> next = tempwp;
- else {
- tempwp -> next = lastw;
- lastw -> next = NULL;
- }
- lastw -> reqs = 0;
- lastw -> bytes = 0.0;
- lastw -> start = tempwp -> start;
- lastw -> start.date += 7;
- if (lastw -> start.date > monthlength[lastw -> start.monthno] +
- ISLEAPFEB(lastw -> start.monthno, lastw -> start.year)) {
- lastw -> start.date -= monthlength[lastw -> start.monthno] +
- ISLEAPFEB(lastw -> start.monthno, lastw -> start.year);
- lastw -> start.monthno++;
- if (lastw -> start.monthno == 12) {
- lastw -> start.monthno = 0;
- lastw -> start.year++;
- }
- }
- lastw -> start.code = timecode(lastw -> start.date,
- lastw -> start.monthno,
- lastw -> start.year, 0, 0);
- }
- lastw -> reqs += reqs;
- lastw -> bytes += bytes;
- }
-
- else /* again, only used if logfile not chronological */
- addweeklydata(year, monthno, date, reqs, bytes);
-
- } /* end if (Wq) */
-
- if (dq) {
- day = dayofdate(date, monthno, year);
- dailyreq[day] += reqs;
- dailybytes[day] += bytes;
- }
- hourlyreq[hr] += reqs; /* no need to bother checking hq */
- hourlybytes[hr] += bytes;
-
-
- if (thistimecode < firsttime.code) {
- firsttime.date = date;
- firsttime.monthno = monthno;
- firsttime.year = year;
- firsttime.hr = hr;
- firsttime.min = min;
- firsttime.code = thistimecode;
- }
-
- if (thistimecode > lasttime.code) {
- lasttime.date = date;
- lasttime.monthno = monthno;
- lasttime.year = year;
- lasttime.hr = hr;
- lasttime.min = min;
- lasttime.code = thistimecode;
- }
- }
-
- /*** Now some routines to sort the various reports ready for printing ***/
- /* First a simple bubblesort for the errors */
- void errsort(int errorder[NO_ERRS])
- {
- extern int errors[NO_ERRS];
-
- int i, j, tempint;
-
- for (i = 0; i < NO_ERRS; i++)
- errorder[i] = i;
-
- for (i = NO_ERRS - 2; i >= 0; i--) {
- for (j = 0; j <= i; j++) {
- if (errors[errorder[j]] < errors[errorder[j + 1]]) {
- tempint = errorder[j];
- errorder[j] = errorder[j + 1];
- errorder[j + 1] = tempint;
- }
- }
- }
- }
-
- double bytefloor(double bytes, char str[])
- {
- double ans;
- int last;
-
- last = MAX((int)strlen(str) - 1, 0);
-
- if (str[last] == '%') {
- str[last] = '\0';
- ans = bytes * atof(str) / 100.0;
- str[last] = '%';
- }
-
- else if (str[last] == 'k' || str[last] == 'K') {
- str[last] = '\0';
- ans = atof(str) * 1024.0;
- str[last] = 'k';
- }
- else if (str[last] == 'M' || str[last] == 'm') {
- str[last] = '\0';
- ans = atof(str) * 1048576.0;
- str[last] = 'M';
- }
- else if (str[last] == 'G' || str[last] == 'g') {
- str[last] = '\0';
- ans = atof(str) * 1073741824.0;
- str[last] = 'G';
- }
- else if (str[last] == 'T' || str[last] == 't') {
- str[last] = '\0';
- ans = atof(str) * 1099511627776.0;
- str[last] = 'T';
- }
-
- else
- ans = atof(str);
-
- return(ans);
- }
-
- int reqfloor(int reqs, char str[])
- {
- int ans;
- int last;
-
- last = MAX((int)strlen(str) - 1, 0);
-
- if (str[last] == '%') {
- str[last] = '\0';
- ans = (int)((double)reqs * atof(str) / 100.0);
- str[last] = '%';
- }
-
- else
- ans = atoi(str);
-
- return(ans);
- }
-
- /* a function to sort the generic reports */
- struct genstruct *gensort(struct genstruct *objhead[], int hashsize,
- int sortby, char minreqstr[], char minbytestr[],
- flag pagesonly, /* for URLs, list only pages? */
- flag alphahost, /* an alphabetical hostsort? */
- int *maxreqs, double *maxbytes, int *maxlength)
- {
- extern char *reversehostname(); /* in alias.c */
- extern flag included(); /* in alias.c */
- extern int hoststrcmp(); /* in utils.c */
-
- extern struct include *ispagehead;
- extern double total_bytes;
- extern int total_succ_reqs;
-
- flag wantit = ON; /* whether we want a particular item */
- struct genstruct *sorthead; /* build up the sort in this list
- (and return it at the end) */
- struct genstruct *p, *p2, *nextp, *lastp;
- int onlist; /* the list we are processing */
- flag finished; /* whether we've finished with a particular entry */
- double floorb = 0.0; /* floor for bytes (for byte sorting) */
- int floorr = 0; /* floor for requests (for other sorting) */
- int outnumber; /* the number of items to be displayed */
-
- int i;
-
-
- /* first calculate the floor */
-
- if (sortby == BYBYTES)
- floorb = bytefloor(total_bytes, minbytestr);
- else
- floorr = reqfloor(total_succ_reqs, minreqstr);
-
- outnumber = 0;
- sorthead = (struct genstruct *)xmalloc(sizeof(struct genstruct));
- sorthead -> name = NULL; /* as marker */
- onlist = 0; /* the list we are on */
- p = objhead[0]; /* starting at list 0 */
- for ( ; onlist < hashsize; p = nextp) {
- /* run through all the objects */
- if (p -> name == NULL) { /* then finished this list */
- nextp = objhead[++onlist]; /* so look at the next list */
- }
- else {
- if (pagesonly) /* only for URLs */ /* if not, wantit is always ON */
- wantit = included(p -> name, ispagehead);
- if ((sortby == BYBYTES && p -> bytes < floorb) ||
- (sortby != BYBYTES && p -> reqs < floorr) ||
- (!wantit)) { /* we don't want it */
- nextp = p -> next;
- }
- else {
- outnumber++;
- *maxreqs = MAX(p -> reqs, *maxreqs);
- *maxbytes = MAX(p -> bytes, *maxbytes);
- if (alphahost) { /* some special things for alphabetical host sort */
- *maxlength = MAX((int)strlen(p -> name), *maxlength);
- if (!isdigit(p -> name[(int)strlen(p -> name) - 1]))
- reversehostname(p -> name);
- }
- if ((sorthead -> name == NULL) ||
- (sortby == RANDOMLY) ||
- (sortby == BYBYTES && p -> bytes > sorthead -> bytes) ||
- (sortby == BYREQUESTS && p -> reqs > sorthead -> reqs) ||
- (sortby == ALPHABETICAL && !alphahost &&
- strcmp(p -> name, sorthead -> name) < 0) ||
- (sortby == ALPHABETICAL && alphahost &&
- hoststrcmp(p -> name, sorthead -> name) < 0)) {
- /* if it's before the first item currently on the list, slot it in */
- nextp = p -> next; /* the next one we're going to look at */
- p -> next = sorthead;
- sorthead = p;
- }
- else { /* otherwise compare with the ones so far */
- finished = OFF;
- lastp = sorthead;
- if (floorb < 0.0)
- i = (int)ROUND(floorb);
- else if (floorr < 0)
- i = floorr;
- else
- i = 1;
- for (p2 = sorthead -> next;
- p2 -> name != NULL && (!finished) && (i++) != -1;
- p2 = p2 -> next) {
- if ((sortby == BYBYTES && p -> bytes > p2 -> bytes) ||
- (sortby == BYREQUESTS && p -> reqs > p2 -> reqs) ||
- (sortby == ALPHABETICAL && !alphahost &&
- strcmp(p -> name, p2 -> name) < 0) ||
- (sortby == ALPHABETICAL && alphahost &&
- hoststrcmp(p -> name, p2 -> name) < 0)) {
- /* if p comes before p2 in the chosen ordering, slot it in */
- nextp = p -> next;
- p -> next = p2;
- lastp -> next = p;
- finished = ON;
- }
- lastp = p2;
- }
- if (!finished) { /* we've reached the end of the list; */
- /* slot it in at the end */
- nextp = p -> next;
- p -> next = p2;
- p2 -> name = NULL;
- lastp -> next = p;
- }
- }
- }
- }
-
- p = nextp; /* so, on to the next one */
-
- } /* end for running through all objects */
-
- if (floorb < 0.0 && outnumber <= -(int)ROUND(floorb) ||
- floorr < 0 && outnumber <= -floorr) {
- /* -ve floor & there are at most that many objects */
- strcpy(minreqstr, "0"); /* signal to output() that we are printing all */
- strcpy(minbytestr, "0");
- }
-
- return(sorthead);
-
- } /* end gensort */
-
- /*** Again, the domain report is a bit different because the
- structure is stored differently ***/
-
- int domsort(void)
- {
- extern int onumber;
- extern struct domain *domainhead[];
- extern int domsortby;
- extern char domminreqstr[];
- extern char domminbytestr[];
- extern double total_bytes;
- extern int total_succ_reqs;
- extern int dom_max_reqs;
- extern double dom_max_bytes;
-
- int i, j, k;
- int firstdom; /* the numerical index of the first domain; we return this */
- int domnextj;
- struct domain *domp, *domlastp;
- int floorr;
- double floorb;
- flag finished;
-
- if (domsortby == BYBYTES)
- floorb = bytefloor(total_bytes, domminbytestr);
- else
- floorr = reqfloor(total_succ_reqs, domminreqstr);
-
- onumber = 0;
- firstdom = DOMHASHSIZE - 2; /* start with unknown domains at front of list */
- if ((domsortby == BYBYTES && (domainhead[firstdom] -> reqs == 0 ||
- domainhead[firstdom] -> bytes < floorb)) ||
- (domsortby != BYBYTES && domainhead[firstdom] -> reqs < floorr))
- /* then we don't want it; set marker */
- domainhead[firstdom] -> reqs = -1;
- dom_max_reqs = domainhead[firstdom] -> reqs;
- dom_max_bytes = domainhead[firstdom] -> bytes;
- domainhead[firstdom] -> nexti = -1;
- j = DOMHASHSIZE - 1; /* the domain we are on; start with numerical domains */
- while (j >= 0) { /* run through all the domains */
- domp = domainhead[j];
- domnextj = domp -> nexti;
- /* the one we're going to look at after this one */
- if (!((domsortby == BYBYTES &&
- (domp -> reqs == 0 || domp -> bytes < floorb)) ||
- (domsortby != BYBYTES && domp -> reqs < floorr))) {
- /* else we don't want it */
- onumber++;
- dom_max_reqs = MAX(domp -> reqs, dom_max_reqs);
- dom_max_bytes = MAX(domp -> bytes, dom_max_bytes);
- if ((domsortby == BYBYTES &&
- domp -> bytes > domainhead[firstdom] -> bytes) ||
- (domsortby == BYREQUESTS &&
- domp -> reqs > domainhead[firstdom] -> reqs) ||
- (domsortby == ALPHABETICAL &&
- strcmp(domp -> id, domainhead[firstdom] -> id) < 0)) {
- /* if it's before the first item currently on the list, slot it in */
- domp -> nexti = firstdom;
- firstdom = j;
- }
- else { /* otherwise compare with the ones so far */
- finished = OFF;
- domlastp = domainhead[firstdom];
- if (floorb < 0.0)
- k = (int)ROUND(floorb);
- else if (floorr < 0)
- k = floorr;
- else
- k = 1;
- for (i = domainhead[firstdom] -> nexti;
- i >= 0 && (!finished) && (k++) != -1;
- i = domainhead[i] -> nexti) {
- if ((domsortby == BYBYTES &&
- domp -> bytes > domainhead[i] -> bytes) ||
- (domsortby == BYREQUESTS &&
- domp -> reqs > domainhead[i] -> reqs) ||
- (domsortby == ALPHABETICAL &&
- strcmp(domp -> id, domainhead[i] -> id) < 0)) {
- /* if domp comes before domp2 in the chosen ordering, slot it in */
- domp -> nexti = i;
- domlastp -> nexti = j;
- finished = ON;
- }
- domlastp = domainhead[i];
- }
- if (!finished) {
- domp -> nexti = -1; /* meaning, last item on the list */
- domlastp -> nexti = j;
- }
- }
- }
-
- j = domnextj; /* so, on to the next one */
-
- } /* end while j >= 0 */
-
- if (floorb < 0.0 && onumber <= -(int)ROUND(floorb) ||
- floorr < 0 && onumber <= -floorr) {
- strcpy(domminreqstr, "0");
- strcpy(domminbytestr, "0");
- }
-
- return(firstdom);
-
- } /* end domsort */
-
- /*** Finally, sort subdomains into the domain report ***/
-
- void subdomsort(void)
- {
- extern int hosttodomcode(); /* in alias.c */
- extern int hoststrcmp(); /* in utils.c */
-
- extern int subonumber;
- extern struct domain *domainhead[], *subdomhead[];
- extern int domsortby;
- extern char subdomminbytestr[], subdomminreqstr[];
- extern double total_bytes;
- extern int total_succ_reqs;
-
- struct domain *subdomp, *subdomnextp, *domp, *domnextp;
- int floorr;
- double floorb;
- int onlist;
- int domcode;
-
- if (domsortby == BYBYTES)
- floorb = bytefloor(total_bytes, subdomminbytestr);
- else
- floorr = reqfloor(total_succ_reqs, subdomminreqstr);
-
- onlist = 0;
- subonumber = 0;
- subdomp = subdomhead[0]; /* starting at list 0 */
- for ( ; onlist < SUBDOMHASHSIZE; subdomp = subdomnextp) {
- /* run through all the subdoms */
- if (subdomp -> name == NULL) { /* then finished this list */
- subdomnextp = subdomhead[++onlist]; /* so look at the next list */
- }
- else if ((domsortby == BYBYTES && subdomp -> bytes >= floorb) ||
- (domsortby != BYBYTES && subdomp -> reqs >= floorr)) {
- subdomnextp = subdomp -> next;
- subonumber++;
- domcode = hosttodomcode(subdomp -> id);
- if (domcode != DOMHASHSIZE - 2) {
- domp = domainhead[domcode]; /* now run through that domain's
- subdomains */
- while (domp -> next -> name != NULL &&
- hoststrcmp(domp -> next -> revid, subdomp -> revid) < 0)
- domp = domp -> next; /* run to right place in alphabet */
- domnextp = domp -> next; /* then slot it in */
- domp -> next = subdomp;
- subdomp -> next = domnextp;
- }
- }
- else
- subdomnextp = subdomp -> next;
- }
- }
-